from twisted.internet import reactor, defer, protocol
from twisted.protocols.basic import LineReceiver
from SmallProtocol_frm import SmallProtocol_framer

import struct
from collections import deque

#---------------------------------------------------------------------------#
# Logging
#---------------------------------------------------------------------------#
from twisted.python import log
from twisted.protocols.policies import TimeoutMixin



class eDIP43A_Async(protocol.Protocol, TimeoutMixin):
   """
   """
   

   def __init__(self):
      ''' Initializes the framer module

      :param framer: The framer to use for the protocol
      '''
      #self.setRawMode()
      self.framer = SmallProtocol_framer() 
      self.lock = defer.DeferredLock()
      self.deferred = None
      self.DEFAULT_TIMEOUT = 1
      
     
      
   def connectionMade(self):
      ''' Called upon a successful client connection.
      '''
      log.msg("Client connected to display")
      
   #----------------------------------------------------------------------
   def failRequests(self, reason):
      """"""
      #self.deferred.errback(reason)
      pass
      
   def timeoutConnection(self):
      self.failRequests(defer.TimeoutError("Connection Timeout"))
      

   def execute(self, request, payload=False, protocol=False):
      ''' Starts the producer to send the next request to
      consumer.write(Frame(request))
      '''
      packet = self.framer.buildPacket(request, protocol)
      #log.msg("TX: " + " ".join([hex(x) for x in packet]))
      #self.setTimeout(1)
      result = self.lock.run(self.sendCommand, packet, payload)
      return result
      
   #----------------------------------------------------------------------
   def sendCommand(self, packet, payload):
      """"""
      
      
      self.deferred = defer.Deferred()
      self.deferred.addCallback(self.parseReply)
      ##self.deferred.addErrback(self.cleanup)
      self.deferred.addBoth(self.cleanup)
      self.setTimeout(self.DEFAULT_TIMEOUT)  
      self.payload = payload
      self.transport.write(packet)
      #self.sendLine(packet)
      return self.deferred     
      
   def dataReceived(self, data):
      ''' Get response, check for valid message, decode result

      :param data: The data returned from the server
      '''
      #log.msg("RX: " + " ".join([hex(ord(x)) for x in data]))
      if self.deferred:
         self.setTimeout(None)
         self.deferred.callback(data)
         # if not, we've timed out or this is a spurious line
         
   #----------------------------------------------------------------------
   def parseReply(self, data):
      """"""
      
      
      #PyByteArray_AsString(data)
      res = self.framer.processIncomingPacket(data, self.payload)
      return res 
   
   def cleanup(self, res):
      self.deferred = None
      #del self.command
      #del self.sent
      del self.payload
      return res   